package com.societyGames.flashForms
{
import com.societyGames.system.EventObject;

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;

/**
 * Are stacked to the right when items are added/removed/change size.
 * Items are given height as assigned.
 **/
public class HorizontalStackContainer extends Sprite implements IChangeSize
{
  private var _desiredHeight:Number;
  private var _desiredWidth:Number;
  private var _sizeChangedEventObject:EventObject;
  private var _items:Vector.<DisplayObject> = new Vector.<DisplayObject>();

  public function HorizontalStackContainer()
  {
    this._sizeChangedEventObject = new EventObject(this, "SIZE_CHANGED");
  }

  /*
   Can only set items at existing indices.
   */
  public function setItemAt(index:int, item:DisplayObject):void
  {
    if (index < 0 || index >= _items.length)
    {
      throw new ArgumentError("Index out of range: " + index);
    }

    //Is item already member of this container?
    var oldIndex:int = _items.indexOf(item);
    if (oldIndex == index) //Already in the right place. Don't do anything.
    {
      return;
    }
    else if (oldIndex != -1)//If it's in another valid position, remove it first.
    {
      removeItemAt(oldIndex);
      if (oldIndex < index) //adjust index
      {
        index--;
      }
    }

    //Remove the old one.
    var oldItem:DisplayObject = _items[index];
    removeChangeSizeListener(oldItem);
    removeChild(oldItem);

    //Put the new one in place.
    _items[index] = item;
    addChangeSizeListener(item);
    this.addChild(item);

    //Recalculate the positions.
    calculate();
  }

  public function addItem(item:DisplayObject):void
  {
    var index:int = _items.indexOf(item);
    //If we don't already have it.
    if (index == -1)
    {
      //Add to the vector.
      _items.push(item);
      //Listen
      addChangeSizeListener(item);
      //Add to display list.
      this.addChild(item);
      //Recalculate graphics.
      calculate();
    }
  }

  public function removeItem(item:DisplayObject):void
  {
    var index:int = this._items.indexOf(item);
    if (index != -1)
    {
      removeItemAt(index);
    }
  }

  private function addChangeSizeListener(item:DisplayObject):void
  {
    var changeSize:IChangeSize = item as IChangeSize;
    if (changeSize != null)
    {
      changeSize.sizeChangedEventObject.addEventListener(childSizeChangedHandler);
    }
  }

  private function removeChangeSizeListener(item:DisplayObject):void
  {
    var changeSize:IChangeSize = item as IChangeSize;
    if (changeSize != null)
    {
      changeSize.sizeChangedEventObject.removeEventListener(childSizeChangedHandler);
    }
  }

  public function removeItemAt(index:int):void
  {
    if (index < 0 || index >= _items.length)
    {
      throw new ArgumentError("Index out of range: " + index);
    }
    var item:DisplayObject = _items[index];
    this._items.slice(index, 1);
    removeChangeSizeListener(item);
    this.removeChild(item);
    calculate();
  }

  private function childSizeChangedHandler(event:Event):void
  {
    calculate();
  }

  public function clearItems():void
  {
    for each (var item:DisplayObject in this._items)
    {
      removeChangeSizeListener(item);
      this.removeChild(item);
    }
    this._items.length = 0;
    calculate();
  }

  //Make all of the items in _items appear correctly.
  private function calculate():void
  {
    var nextX:Number = 0;
    for each (var item:DisplayObject in this._items)
    {
      item.x = nextX;
      item.y = 0;
      nextX += item.width;
    }
    calculateHeight();
    this._sizeChangedEventObject.dispatchEvent();
  }

  private function calculateHeight():void
  {
    for each (var item:DisplayObject in this._items)
    {
      item.height = this._desiredHeight;
    }
  }

  //IChangeSize-->
  public function get sizeChangedEventObject():EventObject
  {
    return this._sizeChangedEventObject;
  }

  //<--IChangeSize

  public override function set height(value:Number):void
  {
    if (value != this._desiredHeight)
    {
      this._desiredHeight = value;
      calculateHeight();
    }
  }

  //The width is pretty much ignored. Perhaps we should try to scale everything down equally to match the width?
  public override function set width(value:Number):void
  {
    if (value != this._desiredWidth)
    {
      this._desiredWidth = value;
    }
  }
}
}